AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include( 'shared.lua' )

function ENT:SpawnFunction( ply, tr )
	if( !tr.Hit ) then return end

	// Get a random class.
	local rnum = math.random(MELON_MINRAND, MELON_MAXRAND)
	local class = MELON_RANDCLASSES[rnum]
	self.color = class["color"]
	self.Range = class["range"]
	self.Multiplier = class["forcemul"]
	self.thinktimemin = class["thinktimemin"]
	self.thinktimemax = class["thinktimemax"]
	self.health = class["health"]
	
	local SpawnPos = tr.HitPos + (tr.HitNormal * 30)
	local ent = ents.Create("melon_npc")
	ent:SetModel( "models/props_junk/Watermelon01.mdl" )
	ent:PhysicsInit(SOLID_VPHYSICS)
	ent:SetMoveType( MOVETYPE_VPHYSICS )
	ent:SetSolid(SOLID_VPHYSICS)
	ent:SetMoveCollide(3)
	ent:SetColor(self.color.r, self.color.g, self.color.b, self.color.a)
	ent:DrawShadow( false ) --less lag
	ent:SetPos( SpawnPos )
	ent:Spawn()
	ent:Activate()
	
	return ent
end

function ENT:Initialize()

	self.Entity:SetModel( "models/props_junk/Watermelon01.mdl" )
	self.Entity:PhysicsInit(SOLID_VPHYSICS)
	self.Entity:SetMoveType( MOVETYPE_VPHYSICS )
	self.Entity:SetSolid(SOLID_VPHYSICS)
	self.Entity:SetMoveCollide(3)
	self.Entity:DrawShadow( false ) --less lag

	local phys = self.Entity:GetPhysicsObject()
	if phys and phys:IsValid() then
		phys:EnableMotion(true)
		phys:Wake()
	end

	local class = MELON_CLASS[2]
	self.color = class["color"]
	self.Range = class["range"]
	self.Multiplier = class["forcemul"]
	self.thinktimemin = class["thinktimemin"]
	self.thinktimemax = class["thinktimemax"]
	self.health = class["health"]

	self.Entity:SetColor(self.color.r, self.color.g, self.color.b, self.color.a)


	self.AIbrush = nil -- The trigger brush it's in.
	self.dir = Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 )
	self.NextChange = CurTime() + math.Rand( 2, 8 )
	self.aHealth = self.health
	self.Normal = Vector( 0, 0, 1 )

	
	if MELONCOUNT >= MAXMELONS then
		local entity = self.Entity
		self.Dead = true
		local function RemoveEntity( entity )
 			if entity and entity:IsValid() then
 				entity:Remove()
 			end
 		end
 		timer.Simple( 5, RemoveEntity, entity )
	 	entity:SetNotSolid( true )
 		entity:SetMoveType( MOVETYPE_NONE )
	 	entity:SetNoDraw( true )
		return
	end

	MELONCOUNT = MELONCOUNT + 1
end

function ENT:Think()
	
	if self.Dead then return end

	self:GetNormal()

	local Ent = self.Entity
	local Pos = self.Entity:GetPos()
	local ents = ents.FindInSphere( Pos, self.Range )
	local players = {}
	for _, ent in pairs( ents ) do
		if ent and ent:IsValid() and ent:GetClass() == "player" then
			local trace = {}
			trace.start = Pos
			local height = 48
			if ent:KeyDown( IN_DUCK ) then
				height = 24
			end
			trace.endpos = ent:GetPos() + Vector( 0, 0, height )
			trace.filter = Ent
			local tr = util.TraceLine( trace )
			if tr.Entity == ent then
				table.insert( players, ent )
			end
		end
	end
	if #players > 0 then
		--ATTACK!
		local ply = players[1]
		if ply != nil then
			local pos = ply:GetPos()
			local melonpos = Ent:GetPos()
			local vect = (pos - melonpos):Normalize()
			self.dir = vect
			self.force = 2500 * self.Multiplier -- Enough force to KILL somebody. Or smash the melon into a thousand pieces.
		end

	elseif self.AIbrush and self.AIbrush.enabled == 1 then
		self.dir = self.AIbrush.dir
		self.force = self.AIbrush.power * self.Multiplier
	else
		self.force = math.random( 2000, 4000 )
		if self.NextChange > CurTime() then return end
		self.dir = Vector( math.Rand( -1, 1 ), math.Rand( -1, 1 ), 0 )
		self.NextChange = CurTime() + math.Rand( 2, 8 )
		
		--Roam around aimlessly
	end
	
	--------
	--JUMP--
	--------
	
	local forward = Vector( self.dir.x, self.dir.y, 0 )
	local up =  Vector( 0, 0, 1 )

	local pos1 = Pos + ( forward * 15 ) - ( up * 2 )	--What's infront of the unit?
	local pos2 = pos1 + ( up * 18 )	--What's above the unit?

	local trace = { start = Pos, endpos = pos1, filter = Ent }	--Trace from the unit to what's infront of the unit.
	local tr = util.TraceLine( trace )

	if tr.HitWorld then	--Something is infront of the unit.
		local arg2 = math.abs( math.abs( self.Normal:Angle().p ) - math.abs( tr.HitNormal:Angle().p ) ) > 75
		if arg2 then	--This something is not the terrain the unit is on.
			trace.start = Pos + ( up * 18 )
			trace.endpos = pos2
			tr = util.TraceLine( trace )
			local arg3 = !tr.HitWorld
			if arg3 then	--The thing infront of the unit is short enough to jump over.
				vel = ( Vector( 0, 0, 1 ) * ( Ent:GetPhysicsObject():GetMass() * 1000 ) )	--Make him hop
				Ent:GetPhysicsObject():ApplyForceCenter( vel )
			end
		end
	end
	
	--------
	--MOVE--
	--------
	
	
	local phys = Ent:GetPhysicsObject()
	if phys and phys:IsValid() then
		phys:ApplyForceCenter( self.dir * self.force )
	end
	
	
	Ent:NextThink( CurTime() + math.Rand( self.thinktimemin, self.thinktimemax ) )
	return true
end

function ENT:OnTakeDamage(dmg)
	self.aHealth = self.aHealth - dmg:GetDamage()
	local attacker = dmg:GetAttacker()
	local ent = self.Entity
	if(self.aHealth <= 0) then
		if attacker:IsPlayer() then
			attacker:AddFrags(1)
		end
		local pos = ent:GetPos()
		ent:Remove()
		// Considering only prop_physics can gib, we can just do this.
		local melon = ents.Create("prop_physics") 
		melon:SetModel("models/props_junk/Watermelon01.mdl")
		melon:SetPos(pos)
		melon:Spawn()
		melon:GibBreakClient(pos)
		melon:Remove()
	end
end

function ENT:OnRemove() -- called when entity is killed
	MELONCOUNT = MELONCOUNT - 1
end

function ENT:GetNormal()

	local vStart = self.Entity:GetPos()

	local trace = {}
 	trace.start = vStart
	trace.endpos = vStart + Vector( 0, 0, -32 )
	trace.filter = self.Entity

	local tr = util.TraceLine( trace )

	if tr.HitWorld then
		self.Normal = tr.HitNormal
	end

end

local linear_damage = {
	[1] = {
		impulse = 150 * 150,
		damage = 1,
	},
	[2] = {
		impulse = 250 * 250,
		damage = 3,
	},
	[3] = {
		impulse = 450 * 450,
		damage = 5,
	},
	[4] = {
		impulse = 550 * 550,
		damage = 10,
	},
	[5] = {
		impulse = 700 * 700,
		damage = 15,
	},
	[6] = {
		impulse = 1000 * 1000,
		damage = 20,
	},
};

local function GetDamage( impulse )
	local damage = 0;
	
	// fetch damage
	for i = 1, table.getn(linear_damage) do
	
		// too high, use the last entry
		if( impulse < linear_damage[i].impulse) then
		
			break;
			
		end
		
		// store damage
		damage = linear_damage[i].damage;
		
	end
	
	return damage;

end
	
function ENT:PhysicsCollide( data, phys )

	// calculate damage
	local our_delta_velocity = data.OurOldVelocity:Length() - phys:GetVelocity():Length();
	local their_delta_velocity = data.TheirOldVelocity:Length() - data.HitObject:GetVelocity():Length();
	
	// didn't have enough umph?
	if( our_delta_velocity > 0 && our_delta_velocity < 20 ) then
	
		our_delta_velocity = 0;
	
	end
	
	// energy
	local energy = ( ( our_delta_velocity ^ 2 ) * phys:GetMass() ) + ( ( their_delta_velocity ^ 2 ) * data.HitObject:GetMass() );
	energy = energy * ( phys:GetInvMass() );
	
	self:TakeDamage( GetDamage( energy ), data.HitEntity );
end

